	title	'tShell (c) 1985 S. Kluger, all rights reserved'
	name	('tShell')
.z80
;
;	prerelease blues:
; start:
;	11/29/85	cold start, drawn up TSHELL.DEF
;	12/01/85	part 1 and 2
;	12/05/85	finished up main code
;	12/08/85	main code bug free
;	12/09/85	first live test, added hook for drive redef
;	12/11/85	completed user area lockout, rewrote TIMECL code
;	12/13/85	completed user 31 exception, added "CNTROL" to
;			prevent access across network for some fcns,
;			added terminal config block and access code
;	12/14/85	moved signon message to login program (from usrsom)
;	12/15/85	added printer/print mode setup
;	12/20/85	added return dskast function
;	12/21/85	added set dskast function, added remote lock
;	12/22/85	added system reset date/time function, added TIMECL
;			suppress code to SCREEN byte
;	12/25/85	fixed AUTUSR bug
;	01/01/86	changed for USRSUP, added fcn 16,17,18,19
;	01/02/86	added sneaky serial # check
;	01/04/86	fixed problem in fcn 15 when date not set
;
; alpha:
; beta:
;	release updates:
;
;
;	serial number/version stuff
;
vers	equ	152h		; version (1.52)
orig	equ	24
unit	equ	623
shel	equ	1		; internal serial #
;
	aseg
?orig?	equ	orig		; set up serial number origin...
?unit?	equ	unit		; and unit.
	public	?orig?,?unit?
;
;
;	+-----------------------+
;	| part 1 - data storage |
;	+-----------------------+
;
;
	dseg
;
	include	TSHELL.DEF
	include TERMINAL.CFG
;
drvtbl:	ds	16*3		; slave's original DSKAST
flag31:	db	0		; user 31 access flag
srhsav:	db	0		; search drive save
;
fcntbl:	dw	xxfc00		; get parameter block
	dw	xxfc01		; set parameter block
	dw	xxfc02		; log off (clear pb and dskast)
	dw	xxfc03		; send console message
	dw	xxfc04		; allow/disallow user 31 access
	dw	xxfc05		; spy on user/attach remote
	dw	xxfc06		; reset this processor
	dw	xxfc07		; abort current process
	dw	xxfc08		; get terminal configuration
	dw	xxfc09		; set terminal configuration
	dw	xxfc10		; return dskast
	dw	xxfc11		; set dskast
	dw	xxfc12		; lock remote attach
	dw	xxfc13		; unlock remote attach
	dw	xxfc14		; return last system reset date/time
	dw	xxfc15		; set reset date/time
	dw	xxfc16		; return master node
	dw	xxfc17		; suspend until date/time
	dw	xxfc18		; execute program
	dw	xxfc19		; return tShell serial number
nmbfcn	equ	($-fcntbl)/2	; number of functions
;
lrsdt:	dw	0		; last reset date
lrstm:	dw	0		;   time
lrsst:	dw	0		;   tick
locked:	db	0		; locked flag
abcpf:	db	0		; flag to abort current process
resflg:	db	0		; reset active flag
twxflg:	db	0		; twix active flag
twxbuf:	ds	128		; twix message buffer
execut:	db	0		; execute flag
execp:	dw	execl
execl:	ds	128		; execute buffer
;
id:	db	'.tShell.'
;
;
;	+-------------------------+
;	| part 2 - initialization |
;	+-------------------------+
;
	common	/?init?/
;
usrin@::
	ld	de,tshpr
	call	crproc##	; create rsp
	ld	a,(autusr##)	; get autusr byte
	and	80h		; see if default logon privileged
	jr	nz,.nsru.	;   do not patch SRUFCN
	ld	a,0c3h		; patch SRUFCN
	ld	(srufcn##+12),a
	ld	hl,sruint
	ld	(srufcn##+13),hl
.nsru.:	ld	hl,timecl	; patch timecl
	ld	(cmdint##+12),hl
	ld	de,drvtbl	; move the dskast
	ld	hl,dskast##
	ld	bc,16*3
	ldir
	ld	a,(srhdrv##)	; get and save search drive
	ld	(srhsav),a
	ld	hl,(conast##+1)	; get console entry point
	ld	(consol),hl	; store it here
	ld	hl,conint	; get intercept address
	ld	(conast##+1),hl	; redirect console
	ld	a,nmbfcn
	ld	hl,id
	ret
;
;	+------------------------+
;	| part 3 - mainline code |
;	+------------------------+
;
	cseg
;
usrfc@::
	push	hl
	push	de
	push	bc
	call	xxfc15
	pop	bc
	pop	de
	pop	hl
	ld	a,l		; get function number
	cp	nmbfcn+1	; in range?
	jr	c,..uok.	;   yes, process fcn
	ld	a,0ffh
	ret
;
..uok.:	ld	h,0		; hl=function #
	add	hl,hl
	push	de		; save de
	ld	de,fcntbl
	add	hl,de		; hl points to fcn address
	pop	de
	ld	a,(hl)
	inc	hl
	ld	h,(hl)
	ld	l,a
	jp	(hl)		; execute function
;
;	+----------------------------------+
;	| function 0 - get parameter block |
;	+----------------------------------+
;
xxfc00:	ld	d,b		; move destination (dma)
	ld	e,c
	ld	hl,LCLID	; point to source
gspb:	ld	bc,128
	ldir
	xor	a		; set ok flag
	ret
;
;	+----------------------------------+
;	| function 1 - set parameter block |
;	|	  and log user on	   |
;	+----------------------------------+
;
xxfc01:	call	cntrol		; see if authorized
	ret	nz
	ld	a,(LCLLGD)	; get logged flag
	or	a		; logged?
	ret	nz		;   yes, barf
	dec	a		; make a=ff
	ld	(LCLLGD),a	; set logged true
	ld	h,b		; move source (dma)
	ld	l,c
	ld	de,LCLID
	call	gspb		; wrap up
	ld	a,(LCLDPR)	; get default printer/queue
	ld	(queptr##),a	; reset it
	ld	a,(LCLDPM)	; get default print mode
	ld	(prtmod##),a	; reset it
	ld	a,(LCLSHD)	; get defined search drive
	ld	(srhdrv##),a	; set new search drive
	call	redef		; effect drive redefinition
	ld	b,8		; 16 drives to process twice
	ld	hl,dskast##	; patch target
	ld	a,(LCLDRA+1)	; get access for A..H
	call	..sds.		; patch
	ld	b,8		; the next 8
	ld	a,(LCLDRA)	; access for J..P
	call	..sds.
	xor	a		; set ok flag
	ret
;
..sds.:	rra			; drive bit into carry
	jr	c,.sdx.		; skip if allowed
	ld	(hl),0ffh	;   else patch to offline
.sdx.:	inc	hl
	inc	hl
	inc	hl		; point to next drive
	djnz	..sds.		; repeat until 8 drives done
	ret
;
;	+----------------------+
;	| function 2 - log off |
;	+----------------------+
;
xxfc02:	call	cntrol		; authorization check
	ret	nz
	ld	hl,LCLID	; clear pb
	ld	b,128
..lof.:	ld	(hl),0
	inc	hl
	djnz	..lof.
	ld	hl,drvtbl	; restore dskast
	ld	de,dskast##
	ld	bc,16*3
	ldir
	xor	a
	ld	(flag31),a	; set 31 access flag off
	ld	a,(srhsav)	; reset search drive
	ld	(srhdrv##),a
	ret
;
;	+-----------------------------------+
;	| function 3 - send console message |
;	+-----------------------------------+
;
xxfc03:	ld	h,b
	ld	l,c
	ld	de,twxbuf
	ld	bc,128
	ldir
	ld	a,0ffh
	ld	(twxflg),a
	ret
;
;	+-----------------------------+
;	| function 4 - user 31 access |
;	+-----------------------------+
;
xxfc04:	call	cntrol		; authorized?
	ret	nz
	ld	hl,flag31	; point to access flag
	ld	a,(hl)		; get it to a
	cpl			; complement (toggle) it
	ld	(hl),a		; save it
	ret			; a returns status
;
;	+--------------------------+
;	| function 5 - spy on user |
;	+--------------------------+
;
xxfc05:	xor	a			; not implemented
	ret
;
;	+----------------------------+
;	| function 6 - reset station |
;	+----------------------------+
;
xxfc06:	ld	a,0ffh
	ld	(resflg),a		; set reset flag
	ret
;
;	+------------------------------------+
;	| function 7 - abort current process |
;	+------------------------------------+
;
xxfc07:	ld	a,0ffh		; set abort flag, so that the guy...
	ld	(abcpf),a	; ...gets blown off at next console I/O
	ret
;
;	+-----------------------------------------+
;	| function 8 - get terminal configuration |
;	+-----------------------------------------+
;
xxfc08:	call	cntrol		; allowed?
	ret	nz		; no, return undone
	ld	d,b		; move destination
	ld	e,c		;   into bc
	ld	hl,TCFBLK	; source to hl
.gspb:	jp	gspb		; move
;
;	+-----------------------------------------+
;	| function 9 - set terminal configuration |
;	+-----------------------------------------+
;
xxfc09:	call	cntrol		; allowed?
	ret	nz		; no, return undone
	ld	h,b		; move source
	ld	l,c		;   into hl
	ld	de,TCFBLK	; set up destination
	jr	.gspb		; move it
;	
;	+-----------------------------+
;	| function 10 - return dskast |
;	+-----------------------------+
;
xxfc10:	call	cntrol		; local call?
	ret	nz		;   no, barf
	ld	d,b		; move destingation
	ld	e,c
	ld	hl,dskast##
	jr	.gspb
;
;	+--------------------------+
;	| function 11 - set dskast |
;	+--------------------------+
;
xxfc11:	call	cntrol		; local call?
	ret	nz		;   no, ignore
	ld	a,(LCLLV)	; get access byte
	and	3		; mask priv level
	sub	2		; see if full
	ret	nz		;   no, ignore
	ld	h,b		; move source
	ld	l,c
	ld	de,dskast##
	ld	bc,16*3
	ldir
	xor	a		; return ok
	ret
;
;	+----------------------------------+
;	| function 12 - lock remote attach |
;	+----------------------------------+
;
xxfc12:	ld	a,(locked)	; get locked flag
	inc	a		; test it
	ret	z		; return if locked
	ld	a,0ffh
.lunl.:	ld	(locked),a	; lock
	ret
;
;	+------------------------------------+
;	| function 13 - unlock remote attach |
;	+------------------------------------+
;
xxfc13:	xor	a
	jr	.lunl.
;
;	+---------------------------------------------+
;	| function 14 - return last system reset time |
;	+---------------------------------------------+
;
xxfc14:	ld	hl,(lrsdt)		; get last reset date
	ld	de,(lrstm)		;   hours and minutes
	ld	bc,(lrsst)		;   seconds and tick count
	ret
;
;	+-----------------------------------+
;	| function 15 - set reset date/time |
;	+-----------------------------------+
;
xxfc15:	ld	c,10
	call	otntry##
	ld	a,0ffh
	bit	7,h
	ret	nz			; invalid date/time
	ld	(lrsdt),hl
	ld	(lrstm),de
	ld	(lrsst),bc
	ld	a,0c9h
	ld	(xxfc15),a		; inhibit re-entry
	ret
;
;	+----------------------------------+
;	| function 16 - return master node |
;	+----------------------------------+
;
xxfc16:	ld	hl,(defdid##)
	ret
;
;	+-----------------------------+
;	| function 17 - suspend until |
;	+-----------------------------+
;
xxfc17:	push	iy
	push	bc			; save pointer to dma buffer
	ld	c,10
	call	otntry##		; get date and time
	pop	iy			; pointer into IY
	ld	a,l
	cp	(iy)
	jr	nz,.17.n		; skip if negative compare
	ld	a,h
	cp	(iy+1)
	jr	nz,.17.n
	ld	a,e
	cp	(iy+2)
	jr	nz,.17.n
	ld	a,d
	cp	(iy+3)
.17.n:	push	iy
	pop	bc
	pop	iy
	ret	z			; return if done
	push	bc
	ld	c,2
	ld	de,60			; else wait a second
	call	otntry##
	pop	bc
	jr	xxfc17
;
;	+------------------------------------+
;	| function 18 - execute command line |
;	+------------------------------------+
;
xxfc18:	ld	h,b
	ld	l,c
	ld	de,execl
	ld	a,(hl)
	or	a
	ret	z
	call	gspb
	ld	hl,execl
	ld	(execp),hl
	ld	a,1
	ld	(execut),a
	ret
;
;	+------------------------------------+
;	| function 19 - return serial number |
;	+------------------------------------+
;
xxfc19:	ld	hl,shel		; return serial #
	ld	de,vers		; and version #
	ld	bc,unit
	ld	a,orig
	ret
;
;
;	+---------------------------+
;	| part 4 - resident process |
;	+---------------------------+
;
;
tshpr:	ld	c,12
	call	otntry##
	ld	hl,unit
	or	a
	sbc	hl,de
	jr	nz,.crash
	ld	c,2			; do it once a second
	ld	de,60
	call	otntry##
	ld	a,(resflg)		; get reset flag
	inc	a
	jr	nz,.tshnr		; skip if no reset
	ld	c,2
	ld	de,240			; delay 4 seconds
	call	otntry##
	call	xreset##		; call external reset
.crash:	di
	halt
;
.tshnr:	ld	a,(twxflg)		; get twix flag
	inc	a
	call	z,sndtwx		; send twix if there
	jp	tshpr			; and loop
;
sndtwx:	ld	hl,twxbuf		; point to buffer
	ld	a,(hl)			; get length
	or	a			; empty?
	ret	z			; yes, return
	ld	b,a
	inc	hl
..stwx:	push	bc
	push	hl
	ld	a,(conast##)
	ld	d,a
	ld	e,2
	ld	c,(hl)
	call	condra##
	pop	hl
	pop	bc
	inc	hl
	djnz	..stwx
;
;
;	+-------------------------+
;	| part 5 - intercept code |
;	+-------------------------+
;
; 1. set user number intercept
;
sruint:	call	chkusr		; check user access
	ret	nc		; ignore if restricted
	ld	(ix+40h),a	;   else store user number
	ret
;
; 2. prompt display intercept
;
timecl:	ld	a,(clblen##+9)
	or	a		;if prompt inhibit...
	jr	nz,skip		;...then don't display time
	ld	a,(LCLSCM)	; get screen byte
	bit	6,a		; see if TIMECL disabled
	jr	nz,skip		;   skip if disabled
	ld	c,10
	call	otntry##	; get time
	ld	a,d		; get hours
	call	bytout
	ld	(timst+1),hl
	ld	a,e		; get minutes
	call	bytout
	ld	(timst+4),hl
	ld	c,12
	call	ocntry##
	ld	a,d
	add	a,'A'
	ld	(sta),a
	ld	a,e
	call	bytout
	ld	(net),hl
	call	dms##
timst:	db	'[00:00 '
sta:	db	'A'
net:	db	'00] ',80h
skip:	ld	a,(ix+40h)
	ret
;
bytout:	ld	l,'0'-1
..l:	inc	l
	sub	10
	jr	nc,..l
	add	a,'0'+10
	ld	h,a
	ret
;
; 3. console I/O intercept
;
conint:	ld	a,(abcpf)	; get abort flag
	inc	a
	jr	nz,.nabrt	; don't abort
	ld	(abcpf),a
	call	dms##		; let the sucker know
	0dh,0ah,0ah,7
	'[OPERATOR TERMINATED]',0dh,0ah,80h
	jp	errxit##	; trash him
;
.nabrt:	ld	a,(execut)
	or	a
	jr	z,.nexec
	call	.exab			; abort whatever we're doing
	ld	a,e
	cp	2
	jr	nc,.nexec
	ld	hl,(execp)
	inc	hl
	or	a
	jr	nz,.exns
	ld	a,(execl)
	or	a
	ret	z
	ld	c,(hl)
	ld	a,0ffh
	ret
;
.exns:	ld	a,(execl)
	dec	a
	ld	(execl),a
	jp	m,doexe
	ld	(execp),hl
	ld	a,(hl)
	ret
;
doexe:	xor	a
	ld	(execut),a
.nexec:	jp	0		; patched later
consol	equ	$-2

;
.exab:	ld	a,0c9h
	ld	(.exab),a
	jp	errxit##
;
;	+------------------------------+
;	| part 6 - utility subroutines |
;	+------------------------------+
;
;
; 1. check user
;    input:  A = desired user area
;    output: C = allowed or NC = restricted
;	     no registers altered
;
chkusr:	and	1fh			; make 0..1f
	push	hl
	ld	hl,LCLLGD
	bit	7,(hl)
	pop	hl
	scf
	ccf
	ret	z		; exit if unlogged
	cp	31		; user 31 requested?
	jr	nz,n.31.	;   no, continue normally
	push	hl
	ld	hl,flag31	; point to user 31 access flag
	inc	(hl)
	dec	(hl)
	pop	hl		; Z if flag off
	jr	z,n.31.		; check if maybe authorized anyway
	scf
	ret			; say yes
;
n.31.:	push	bc
	push	hl
	ld	c,a		; save requested user area
	ld	a,(LCLLV)	; get his access level
	and	3		; mask acl
	cp	2		; check if full access
	ld	a,c
	scf			; preset true
	jr	z,.n.res	; skip if authorized
	cp	8		; over 7?
	ld	hl,LCLUSA
	jr	c,..ck..
	cp	16		; over 15?
	inc	hl
	jr	c,..ck..
	cp	24		; over 23
	inc	hl
	jr	c,..ck..
	inc	hl
..ck..:	and	7		; make 0..7
	ld	b,a		; into counter
	inc	b		; iterate at least once
	ld	a,(hl)		; get access bits
..ckl.:	rra			; move bits around
	djnz	..ckl.		;   until right one is in CY
	ld	a,c		; get user area back
.n.res:	pop	hl		; restore hl
	pop	bc		; restore bc
	ret
;
; 2. dskast patch for drive re-definition
;    no input, output, all regs used
;    NOTE: for testing, redef is allowed for A:
;
redef:
	ret			; later

;
; 3. check for authorization.
;    a call here verifies that DE=FFFF
;
cntrol:	inc	de
	ld	a,d
	or	e
	ld	a,0ffh		; set false
	ret



	end
		; check if maybe authorized anyway
	scf
	ret			; say yes
;
n.31.:	push	bc
	push